﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Windows.Threading;
using Microsoft.Phone.Tasks;
using TheVerge.Base;
using System.Text;
using System.Windows.Media;
using TheVerge.Phone.Converters;
using TheVerge.Phone.Controls;
using TheVerge.Base.Models;
using TheVerge.Base.Platform;
using System.Windows.Data;

namespace TheVerge.Phone.Pages
{
    public partial class PodcastPage : BasePage
    {
        private FromNowDateTimeConverter _conv = new FromNowDateTimeConverter();
        private DispatcherTimer _timer = new DispatcherTimer();
        private volatile bool _canUpdatePosition = true;

        #region HTML
        /// <summary>
        /// http://social.msdn.microsoft.com/forums/en-us/wpdevelop/thread/3c5107dc-f286-4d5d-98dd-0c688bd4f5e0
        /// Special thanks to that forum post to help see the value of including the doctype in the web browser control.
        /// </summary>
        private const string HTML = @"
<!DOCTYPE html PUBLIC ""-//WAPFORUM//DTD XHTML Mobile 1.2//EN"" ""http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd"">
<html>
	<head>
		<meta name=""viewport"" content=""width=480"" />
		<style type=""text/css"">
			body {{
				background-color:{0};
				color:{1};
				font-size:128%;
			}}
			a {{ color:{2}; }}

			.Title {{
				font-size:176%;
				color:{2};
			}}

			.Subtle {{
				color:{3};
			}}

			.SourceName {{
				background-color:{2};
				border:2px solid {0};
				color:{0};
				padding:3px 5px;
				float: left;
			}}

			.SourceLinkDiv {{
				background-color:{3};
				border:2px solid {0};
				padding:3px 5px;
				float: left;
			}}

			.SourceLink {{ 
				text-decoration:none;
				color:{0};
			}}

		</style>
	</head>

	<body>{4}</body>
	<script>
			window.onload = function() {{
				a = document.getElementsByTagName('a');
				for(var i=0; i < a.length; i++) {{
					a[i].attachEvent('onclick', notify);
					
				}}
			}}

			function notify(evt) {{
				window.external.Notify(evt.srcElement.href); 

				if (evt) {{
					evt.returnValue = false;
				}} 
				
				return false;
			}}
		</script>	
</html>";
        #endregion

        public PodcastPage()
        {
            InitializeComponent();
            _timer.Interval = TimeSpan.FromSeconds(0.5);
            _timer.Tick += new EventHandler(UpdateState);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            var podcast = GetActivePodcast();

            _timer.Start();
            UpdateState(null, null);

            webBrowser.NavigateToString(CreateHtml(podcast));

            App.MainVM.Media.Podcasts.PlayStateChanged += Podcasts_PlayStateChanged;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            App.MainVM.Media.Podcasts.PlayStateChanged -= Podcasts_PlayStateChanged;
            _timer.Stop();
        }

        #region Event Handlers
        private void Rewind_Click(object sender, RoutedEventArgs e)
        {
            var podcast = GetActivePodcast();
            podcast.Rewind();
        }

        private void Forward_Click(object sender, RoutedEventArgs e)
        {
            var podcast = GetActivePodcast();
            podcast.FastForward();
        }

        private void Play_Click(object sender, RoutedEventArgs e)
        {
            var podcast = GetActivePodcast();
            podcast.PlayPause();
        }

        private void Podcasts_PlayStateChanged(object sender, EventArgs e)
        {
            UpdateState(null, null);
        }

        private void PositionIndicator_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _canUpdatePosition = false;
        }

        private void PositionIndicator_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
        {
            _canUpdatePosition = false;
        }

        private void PositionIndicator_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
        {
            var podcast = GetActivePodcast();
            var ts = TimeSpan.FromSeconds(positionIndicator.Value);

            podcast.Seek(ts);

            _canUpdatePosition = true;
        }
        #endregion

        private void UpdateState(object sender, EventArgs e)
        {
            var podcast = GetActivePodcast();

            var podcasts = App.MainVM.Media.Podcasts;

            if (!podcasts.IsActiveTrack(podcast))
            {
                btnPP.ContentTemplate = (DataTemplate)App.Current.Resources["dtPlay"];
                positionIndicator.Value = 0;
                positionIndicator.Maximum = int.MaxValue;
                positionIndicator.IsEnabled = false;
                return;
            }

            positionIndicator.IsEnabled = true;

            switch (podcasts.PlayState)
            {
                case AudioPlayState.Playing:
                    btnPP.ContentTemplate = (DataTemplate)App.Current.Resources["dtPause"];
                    break;

                case AudioPlayState.Paused:
                    btnPP.ContentTemplate = (DataTemplate)App.Current.Resources["dtPlay"];
                    break;
                case AudioPlayState.Rewinding:
                case AudioPlayState.FastForwarding:
                    btnPP.ContentTemplate = (DataTemplate)App.Current.Resources["dtPlay"];
                    break;
            }

            // Set the current position on the ProgressBar.
            var position = podcasts.CurrentAudioPosition;
            var duration = podcasts.CurrentAudioDuration;

            if (positionIndicator.Maximum != duration.TotalSeconds)
            {
                positionIndicator.Maximum = duration.TotalSeconds;
                ((TotalSecondsFriendStringConverter)Resources["remainingConv"]).Duration = duration;
            }
            
            if(_canUpdatePosition)
                positionIndicator.Value = position.TotalSeconds;
        }

        private VMPodcast GetActivePodcast() { return App.MainVM.Media.Podcasts.ActivePodcast; }

        #region Browser & Content Display
        private string CreateHtml(VMPodcast e)
        {
            var sb = new StringBuilder();
            sb.AppendFormat("<p class='Title'>{0}</p>", e.Title);
            sb.AppendFormat("<p>By <bold>{0}</bold> <span class='Subtle'>{1}</span></p>", e.Author, _conv.Convert(e.PublishedOn, null, null, null));
            var body = CleanBody(e.Body);
            sb.Append(body);
            sb.Append(@"<br />");
            sb.Append(@"<br />");

            return string.Format(HTML, GetHex(BackColor), GetHex(ForegroundColor), GetHex(AccentColor), GetHex(SubtleColor), sb);
        }

        private Color AccentColor { get { return ThemeManager.Accent; } }
        private Color BackColor { get { return ThemeManager.Background; } }
        private Color ForegroundColor { get { return ThemeManager.Foreground; } }
        private Color SubtleColor { get { return ThemeManager.Subtle; } }

        private static string GetHex(Color c)
        {
            return string.Format("#{0:X2}{1:X2}{2:X2}", c.R, c.G, c.B);
        }

        private static string CleanBody(string body)
        {
            if (string.IsNullOrEmpty(body)) return string.Empty;

            var rssIndex = body.IndexOf(@"<p><br id=");

            if (rssIndex > 0)
                return body.Substring(0, rssIndex);

            return body;
        }

        private void theBrowser_ScriptNotify(object sender, Microsoft.Phone.Controls.NotifyEventArgs e)
        {
            try
            {
                var wbt = new WebBrowserTask();
                wbt.Uri = new Uri(e.Value, UriKind.Absolute);
                wbt.Show();
            } //-- Sometimes we may get an invalid Uri, as a result, we need to catch this exception.
            catch (Exception)
            {
                MessageBox.Show("Unable to launch link. This could be do to a poorly formatted Uri or an invalid protocol.");
            }
        }
        #endregion

        protected override bool IsMini { get { return false; } }
        protected override IEnumerable<IApplicationBarIconButton> Buttons  { get { return null; } }
        protected override IEnumerable<IApplicationBarMenuItem> MenuItems { get { return null; } }
    }

    public class TotalSecondsFriendStringConverter : IValueConverter
    {
        private const string FS = @"{0:d2}:{1:d2}:{2:d2}";
        public TimeSpan Duration { get; set; }

        public TotalSecondsFriendStringConverter()
        {
            Duration = TimeSpan.Zero;
        }
        
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                var d = (double)value;
                var ts = TimeSpan.FromSeconds(d);

                if(Duration != TimeSpan.Zero)
                    return GetTimeRemainingString(ts, Duration);

                return GetString(ts, FS);
            }
            catch { return value; }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        private static string GetTimeRemainingString(TimeSpan position, TimeSpan duration)
        {
            var remaining = duration - position;

            if (remaining < TimeSpan.Zero) return string.Empty;

            return GetString(remaining, "-" + FS);
        }

        private static string GetString(TimeSpan ts, string fs)
        {
            return string.Format(fs, ts.Hours, ts.Minutes, ts.Seconds);
        }
    }
}